#!/usr/bin/python
#
#--------------------------------------------------------------------
# Data Structures
#--------------------------------------------------------------------
# label: { 
#     url: url,
#     stuffs: 
#     {
#        item : { pattern:pattern, message:message, expression:[lambda, p1, p2], matched:[ val, ref ] },
#        ...
#     },
#     contact:[ from, to, topic ]
# }
#
#---------------------------------------------------------------------
# Class Structures
#---------------------------------------------------------------------
#
# ** Warehouse  
#       {   
#           @doorplate:
#           {
#               @label:box,
#               ...
#           }
#
# ** box   
#       {
#           @url:url,
#           @stuffs: {
#               @@item:stuff,
#               ...
#           }
#           @contact: [ from, to, topic ]
#       }
#
# ** sutff
#       { 
#           @pattern:pattern
#           @message:message
#           @expression: [ lambda, p1, p2 ]
#           @matched: [ val, ref ]}
#       }
#
#---------------------------------------------------------------------
from google.appengine.api import memcache
import logging
from Predef import Predef as PRE

####################################################
# stuff
####################################################
class stuff:
    ############
    # Initialize
    ############
    def __init__(self, pattern, message, expression):
        self.pattern = pattern
        self.message = message
        self.expression = PRE.checkExpression(expression)
        self.matched = list(PRE.matched_)

    def update(self, s):
        self.pattern = s.pattern
        self.message = s.message
        self.expression = PRE.checkExpression(s.expression)
        #self.matched = PRE.checkMatched(s.matched)
 
    ############
    # verify
    ############
    def isValid(self):
        return (self.pattern!='') and (self.message!='') and (self.expression[0]!='') 

    ############
    # scatter & gather
    ############
    def set(self,value):
        self.matched[0]=value

    def getPattern(self):
        return self.pattern

    def getMessage(self):
        return self.message

    def getExpression(self):
        return PRE.checkExpression(self.expression)

    def getMatched(self):
        return PRE.checkMatched(self.matched)

    def setMatched(self, m):
        self.matched=PRE.checkMatched(m)

    ############
    # process
    ############
    def export(self):
        # pattern
        p="'{}'".format("':r'".join([PRE.pattern , self.pattern]))
        # message
        m="'{}'".format("':'".join([PRE.message , self.message]))
        #expression
        e="'"+PRE.expression+"':"+"[r'{}']".format("','".join(PRE.checkExpression(self.expression)))
        # matched
        c="'"+PRE.matched+"':"+"['{}']".format("','".join(self.matched))
        # stuff
        return "{"+",".join([p,m,e,c])+"}"

    def keepref(self):
        self.matched[1]=self.matched[0]


####################################################
# box
####################################################
class box:

    ############
    # Initialize
    ############
    def __init__(self,label):
        self.label=label
        self.url=PRE.url_
        self.contact=list(PRE.contact_)
        self.stuffs=dict()

    def update(self, pack):
        self.url=pack[PRE.url]
        self.contact=pack[PRE.contact]
        for k,v in pack[PRE.stuffs].items():
            self.addItem(k, v[PRE.pattern], v[PRE.message], v[PRE.expression], v[PRE.matched])
        return self

    ############
    # verify
    ############
    def isValid(self):
        for s in self.stuffs.values():
            if not s.isValid():
                return False
        return True

    ############
    # scatter & gather
    ############
    def getUrl(self):
        return self.url

    def setUrl(self,url):
        if PRE.isValidHttp(url):
            self.url=url
            return True
        else:
            return False

    def getLabel(self):
        return self.label

    def setContact(self,fr,to,tp):
        if PRE.isValidEmail(fr) and PRE.isValidEmail(to):
            self.contact[0]=fr 
            self.contact[1]=to
            self.contact[2]=tp
            return True
        else:
            return False

    def setTo(self,to,tp):
        if PRE.isValidEmail(to):
            self.contact[1]=to
            self.contact[2]=tp
            return True
        else:
            return False

    def getContact(self):
        return self.contact

    #def setLabel(self,label):
    #    self.label=label

    ############
    # set up Items
    ############
    def delItem(self, item):
        if item in self.stuffs:
            del self.stuffs[item]
            return True
        else:
            logging.error("Failed to delItem, because <%s> has been found in lists.", item)
            #raise NameError, item
        return False

    def addItem(self, item, pattern, message, expression, matched=None):
        if (item != '') and (item not in self.stuffs):
            s=stuff(pattern, message, PRE.checkExpression(expression))
            if matched is not None:
                s.setMatched(matched)
            if s.isValid():
                self.stuffs[item]=s
                return True
            else:
                logging.error("Failed to addItem, because it was invalid.")
        else:
            logging.error("Failed to addItem, because <%s> has existed.", item)
            #raise NameError, item
        return False

    def updateItem(self, item, pattern, message, expression):
        if item in self.stuffs:
            s=stuff(pattern, message, PRE.checkExpression(expression))
            if s.isValid():
                self.stuffs[item].update(s)
                return True
            else:
                logging.error("Failed to updateItem, because it was invalid.")
        else:
            logging.error("Failed to updateItem, because <%s> has been found in lists.", item)
            #raise NameError, item
        return False

    def setItemValue(self, item, value):
        if item in self.stuffs:
            self.stuffs[item].set(value)
            return True
        else:
            logging.error("Failed to setItemValue, because <%s> has been found in lists.", item)
            #raise NameError, item
        return False

    ############
    # process
    ############
    def keepref(self):
        for stuff in self.stuffs.values():
            stuff.keepref()

    def export(self):
        # url
        u="'{}'".format("':'".join([PRE.url , self.url]))
        # stuffs
        #",".join("'{0}':{1}".format(k,v.out()) for k,v in items.items()
        s="'" + PRE.stuffs + "':{" + ",".join("'{0}':{1}".format(k,v.export()) for k,v in self.stuffs.items())+"}"
        # contact
        c="'" + PRE.contact + "':"+"['{}']".format("','".join(self.contact))
        # box
        #return "'"+self.label+"':{"+",".join([u,s,c])+"}"
        return "{{{}}}".format(",".join([u,s,c]))


####################################################
# Warehouse for datastore or memcache
####################################################
class Warehouse:
    ############
    # Initialize
    ############
    def __init__(self,namespace):
        self.namespace=namespace
        self.namelist=memcache.get("namelist", namespace=self.namespace)
        if self.namelist is None:
            self.namelist=[]

    ############
    # verify
    ############
    def ISEXIST(self,label):
        return (label in self.namelist)

    ############
    # scatter & gather
    ############
    def CHECKIN(self, label, box):
        if label == '':
            logging.error("Pleas name the box first!")
            return False
        if label in self.namelist:
            #logging.info("Update {0} into memcache<{1}".format(label,self.namespace))
            return memcache.set(label,box,namespace=self.namespace)
        else:
            #logging.info("Add {0} into memcache<{1}".format(label,self.namespace))
            self.namelist.append(label)
            memcache.set("namelist",self.namelist,namespace=self.namespace)
            return memcache.add(label,box,namespace=self.namespace)

    def CHECKOUT(self, label):
        if (label is not None) and (label != ''): 
            return memcache.get(label,namespace=self.namespace)
        else:
            return None

    def List(self):
        return list(self.namelist)

    ############
    # process
    ############
    def DESTROY(self,label):
        if label in self.namelist:
            logging.info("Destroy {0} from memcache<{1}".format(label,self.namespace))
            self.namelist.remove(label)
            memcache.set("namelist",self.namelist,namespace=self.namespace)
            memcache.delete(label,namespace=self.namespace)
        else:
            logging.error("Can't delete the {0} into memcache<{1}, because it is not exist".format(label,self.namespace))
